package cloudspace.vm.javassist;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.Loader;
import javassist.NotFoundException;

import org.apache.log4j.Logger;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.WebApp;


/**
 * The javassist loader class loads a javassist configuration and then applies
 * it to loaders. These configuration files are loaded from the config/javassist
 * folder. They are loaded staticly at start. There is also a logger initialized
 * to handle all logging that is needed from javassist classes.
 */
public abstract class JavassistBootloader
{
    protected static Logger logger = Logger.getLogger( JavassistBootloader.class );

    /** The ee factory. */
    private static TranslatorProvider eeFactory = TranslatorProvider.getExprEditorFactory();

    private static ClassPool proxyPool;


    /**
     * Adds a config file to the Javassist Loader. These configuration files are
     * used to load configurable translators on class loaders.
     * 
     * @param configFile
     *            the config file to add to list of loaders
     */
    public static void addConfigFile( File configFile )
    {
        try
        {
            // Logger.logInfo(configFile.getAbsolutePath());
            eeFactory.addConfigFile( configFile, proxyPool );
        }
        catch ( IOException e )
        {
            logger.error( "Bad Configfile:  " + configFile, e );
        }
    }


    /**
     * This method adds configurable translators to the passed loader. This
     * translator is created using the loaded configuration files.
     * 
     * @param localClassLoader
     *            the classloader to be translated.
     * @param localClassPool
     *            the class pool to find classes required for translations
     * 
     * @throws MalformedConfigurationException
     *             the malformed configuration exception
     */
    public static void translateClasses(
        Loader localClassLoader,
        ClassPool localClassPool ) throws MalformedConfigurationException
    {
        logger.info( "Translating Classes" );
        List<ConfigurableTranslatorLoader> translators = eeFactory.getTranslators();
        for ( ConfigurableTranslatorLoader curTranslator : translators )
        {
            try
            {
                localClassLoader.addTranslator( localClassPool, curTranslator );
            }
            catch ( CannotCompileException e )
            {
                logger.error( "Initialization of the Translator failed", e );
            }
            catch ( NotFoundException e )
            {
                logger.error( "The CtClass was not found", e );
            }
        }

    }


    public static String getProxy( String className )
    {

        CtClass proxy = eeFactory.getProxy( className );
        if ( proxy != null )
            return proxy.getName();
        return null;
    }


    public static ClassPool getProxyPool()
    {
        return proxyPool;
    }

    static
    {
        String configPath = "";
        proxyPool = new ClassPool();
        try
        {
            if ( Executions.getCurrent() != null )
            {
                WebApp app = Executions.getCurrent().getDesktop().getWebApp();

                proxyPool.appendClassPath( app.getRealPath( "/WEB-INF/classes" ) );
                proxyPool.appendClassPath( app.getRealPath( "/WEB-INF/lib" )
                    + "/*" );
                configPath = app.getRealPath( "configs/javassist" );
            }
            else
            {
                proxyPool.appendClassPath( "src" );
                configPath = "resources/configs/javassist";
            }
        }
        catch ( NotFoundException e )
        {
            logger.error( "The source path was not found", e );
        }
        proxyPool.appendSystemPath();
        File configDir = new File( configPath );
        File[] directoryContents = configDir.listFiles();
        for ( File configFile : directoryContents )
        {
            if ( configFile.getName().endsWith( ".conf" ) )
                JavassistBootloader.addConfigFile( configFile );
        }

    }

}
